const gulp = require("gulp");
const path = require("path");
const lazypipe = require("lazypipe");
import mockApi from './server/index';
const $ = require("gulp-load-plugins")({
  DEBUG: true, // 默认 false 设置为true时，该插件会将信息记录到控制台。 对于错误报告和问题调试很有用
  //   pattern: ['gulp-*', 'gulp.*', '@*/gulp{-,.}*'], // 将会去搜索的数据
  //   overridePattern: true, // 如果为true，则覆盖内置模式。 否则，扩展内置模式匹配器列表。
  //   config: 'package.json', // 定义从哪里搜索插件
  //   scope: ['dependencies', 'devDependencies', 'peerDependencies'], //在被搜索的文件中要去查看哪些键值
  //   replaceString: /^gulp(-|\.)/, // 将模块添加到上下文时要从模块名称中删除的内容，例如gulp-rename在使用是为$.rename()即可，无需前缀
  //   camelize: true, //如果为true，则将带连字符的插件名称转换为驼峰式
  // lazy: true, // 插件是否应按需延迟加载
  //   rename: {}, //重命名插件的映射
  //   renameFn: function (name) { ... }, //处理插件重命名的功能（默认有效）
  //   postRequireTransforms: {}, // see documentation below
  //   maintainScope: true // 切换加载所有npm范围，如非作用域包
});


// const imagemin = require("gulp-imagemin");

// 与 Bower 结合使用
const mainBowerFiles = require("main-bower-files");
const browserSync = require("browser-sync").create();
const es = require("event-stream");
const log = require("fancy-log");

const isDev = process.env.NODE_ENV === "development";
const resolve = (dir) => {
  return path.join(__dirname, dir);
};

/**
 * @src 查找目录，需处理的源文件，多文件时可以是数组或正则的形式
 * @desc 输出目录，其参数只能用来指定要生成的文件的目录，而不能指定生成文件的文件名，它生成文件的文件名使用的是导入到它的文件流自身的文件名
 */
const paths = {
  html: {
    input: resolve("src/**/*.html"),
    output: resolve("dist"),
    // watch: "src/pug/**/*.pug",
  },
  ejs: {
    input: resolve("src/**/*.{ejs, html}"),
    output: resolve("dist"),
    // watch: "src/pug/**/*.pug",
  },
  scss: {
    input: resolve("src/**/*.{scss, sass}"),
    output: resolve("dist"),
    // watch: "src/less/**/*.less",
  },
  js: {
    input: resolve("src/**/*.js"),
    output: resolve("dist/js"),
    // watch: "src/js/**/*.js",
  },
  cssInject: {
    cssInput: resolve("dist/**/*.css"),
    htmlInput: resolve("dist/**/*.html"),
    output: resolve("dist"),
  },
  images: {
    src: "src/img/**/*",
    dest: "dist/img/",
    watch: "src/img/**/*",
  },
  clean: {
    input: [resolve("dist"), resolve("rev"), resolve("tmp")],
  },
  copy: {
    input: resolve("src/assets/**/*"),
    output: resolve("dist"),
  },
  favicons: {
    input: resolve("src/assets/images/favicons.png"),
    output: resolve("dist"),
  },
  server: {
    input: resolve("dist"),
  },
};
const cssChannel = lazypipe()
  // .pipe(() =>
  //   $.base64({
  //     baseDir: "public",
  //     extensions: ["svg", "png", /\.jpg#datauri$/i],
  //     exclude: [/\.server\.(com|net)\/dynamic\//, "--live.jpg"],
  //     maxImageSize: 8 * 1024,
  //     debug: true,
  //   })
  // )
  .pipe(() => {
    if (isDev) {
      return $.postcss([require("autoprefixer")]);
    }
    return $.postcss([
      require("autoprefixer"),
      require("cssnano")({
        preset: "default",
      }),
    ]);
  });
const sassChannel = lazypipe()
  .pipe($.sassGlob)
  .pipe(() => sass().on("error", sass.logError));
const imageChannel = lazypipe().pipe(() => {
  imagemin(
    [
      imagemin.gifsicle({ interlaced: true }),
      imagemin.mozjpeg({ quality: 75, progressive: true }),
      imagemin.optipng({ optimizationLevel: 5 }),
      imagemin.svgo({
        plugins: [{ removeViewBox: true }, { cleanupIDs: false }],
      }),
    ],
    {
      verbose: true,
    }
  );
});

gulp.task("html", () => {
  const { input, output } = paths.html;
  return (
    gulp
      .src(input)
      // 读取文件后面加入 plumber
      .pipe($.plumber())
      .pipe(
        $.if(
          !isDev,
          $.htmlmin({
            removeComments: true, // 清除 HTML 注释
            collapseWhitespace: true, // 压缩空格
            collapseBooleanAttributes: true, // 省略布尔属性的值，如 <input checked="true"/> => <input checked/>
            removeEmptyAttributes: true, // 删除所有空格作属性值，如 <input id=""> => <input>
            removeScriptTypeAttributes: true, // 删除 <script> 的 type="text/javascript" 属性
            removeStyleLinkTypeAttributes: true, // 删除 <style> 和 <link> 的 type="text/css" 属性
            minifyJS: true, // 压缩页面 JavaScript
            minifyCSS: true, // 压缩页面 CSS
          })
        )
      )
      // .pipe(htmlChannel())
      .pipe(gulp.dest(output))
  );
});

gulp.task("js", () => {
  const { input, output } = paths.js;
  return gulp
    .src(input)
    .pipe($.plumber())
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.eslint.failAfterError())
    .pipe($.filter("**/src/*.js"))
    .pipe($.babel())
    .pipe($.if(!isDev, $.uglify()))
    .pipe(gulp.dest(output));
});

gulp.task("ejs", () => {
  const { input, output } = paths.ejs;
  return (
    gulp
      .src(input)
      .pipe($.plumber())
      .pipe($.filter(["**/src/*.ejs", "**/views/*.ejs"]))
      .pipe($.ejs())
      .pipe(
        $.rename((path) => {
          log(JSON.stringify(path));
          return {
            dirname: path.dirname,
            basename: path.basename,
            extname: ".html",
          };
        })
      )
      // .pipe($.inject(sources))
      .pipe(gulp.dest(output))
      .pipe(browserSync.reload({ stream: true }))
  );
});

gulp.task("scss", () => {
  const { input, output } = paths.scss;
  const filter = $.filter("**/src/*.scss", { restore: true });
  return gulp
    .src(input)
    .pipe($.plumber())
    .pipe(
      $.stylelint({
        failAfterError: true, // 默认 true
        reporters: [{ formatter: "string", console: true }], // 默认 []
        debug: true, // 默认 false
      })
    )
    .pipe(filter)
    .pipe(sassChannel())
    .pipe(cssChannel())
    .pipe(gulp.dest(output))
    .pipe(filter.restore)
    .pipe($.filter("**/views/*.scss"))
    .pipe(sassChannel())
    .pipe(cssChannel())
    .pipe(
      $.rename((path) => {
        log(JSON.stringify(path));
        // 更改Gulp中文件的目标路径(Change the destination path of files in Gulp)
        return {
          dirname: "/css",
          basename: path.basename,
          extname: path.extname,
        };
      })
    )
    .pipe(gulp.dest(output));
});

gulp.task("inject", () => {
  const { htmlInput, cssInput, output } = paths.cssInject;
  return (
    gulp
      .src(htmlInput)
      // .pipe(
      //   es.map((file, cb) => {
      //     log(path.basename(file.path));
      //     log(path.dirname(file.path));
      //     log(path.extname(file.path));
      //     return cb();
      //   })
      // )
      .pipe(
        $.inject(gulp.src(cssInput, { read: false }), {
          relative: true,
          removeTags: true,
          transform: function (filepath, file, index, length, targetFile) {
            const cssName = path.basename(filepath);
            const htmlName = path.basename(targetFile.path);
            if (htmlName.slice(0, -5) === cssName.slice(0, -4)) {
              return $.inject.transform.apply($.inject.transform, arguments);
            }
          },
        })
      )
      .pipe(gulp.dest(output))
  );
});

gulp.task("bower", () => {
  return (
    gulp
      // .src(mainBowerFiles())
      .src(
        mainBowerFiles({
          overrides: {
            vue: {
              // 插件名称
              main: "dist/vue.js", // 对应的文件路径
            },
          },
        })
      )
      // 输出到临时文件夹 tmp/vendors
      .pipe(gulp.dest("./tmp/vendors"))
  );
});

/**
 * 第一步，重置 task：删除上一次构建遗留的痕迹
 * 清空文件夹
 * 因为打包只会覆盖改变的文件，在 src 中删除的文件，在 dist 中会依然存在
 */
gulp.task("clean", () => {
  const { input } = paths.clean;
  return gulp
    .src(input, {
      read: false, // 默认 true
      allowEmpty: true, // 默认 false
    })
    .pipe($.plumber())
    .pipe($.clean())
    .pipe($.notify("Found file: <%= JSON.stringify(file) %>!"));
  // .pipe($.notify("文件已清空!"));
});

gulp.task('clean', () => {
  return del(['dist']);
});

gulp.task("copy", () => {
  const { input, output } = paths.copy;
  const cssFilter = $.filter("**/*.css", { restore: true });
  const imageFilter = $.filter("**/*.{png, jpg, gif, svg}", { restore: true });
  const filter = $.filter(["**", "!*.css"]);
  return gulp
    .src(input)
    .pipe($.plumber())
    .pipe(imageFilter)
    .pipe(imageChannel)
    .pipe(gulp.dest(output))
    .pipe(imageFilter.restore)
    .pipe(cssFilter)
    .pipe(cssChannel())
    .pipe(gulp.dest(output))
    .pipe(cssFilter.restore)
    .pipe(filter)
    .pipe(gulp.dest(output));
  // .pipe($.notify("拷贝完成!"));
});

gulp.task("favicons", () => {
  const { input, output } = paths.favicons;
  return gulp
    .src(input)
    .pipe(
      $.favicons({
        appName: "My App",
        appShortName: "App",
        appDescription: "This is my application",
        developerName: "Hayden Bleasel",
        developerURL: "http://haydenbleasel.com/",
        background: "#020307",
        path: "favicons/",
        url: "http://haydenbleasel.com/",
        display: "standalone",
        orientation: "portrait",
        scope: "/",
        start_url: "/?homescreen=1",
        version: 1.0,
        logging: false,
        html: "index.html",
        pipeHTML: true,
        replace: true,
      })
    )
    .pipe(gulp.dest(output));
});

/**
 * 静态服务器
 * [Browsersync] Access URLs:
 * -------------------------------------
 *       Local: http://localhost:3000
 *    External: http://192.168.1.55:3000
 * -------------------------------------
 *          UI: http://localhost:3001
 * UI External: http://localhost:3001
 * -------------------------------------
 * [Browsersync] Serving files from: D:\frontend\gulp-demo\dist
 * 说明:
 * 1. Local: http://localhost:3000
 *    1. 默认打开此服务器地址
 *    2. 默认端口是 3000，如果端口号被占用，则自动打开3001，依次类推
 * 2. External: http://169.254.109.182:3000
 *    1. 此地址可用于手机访问
 *    2. 需要手机调试时，可以访问这个地址，但手机和电脑要在同一 wifi 网络
 */
gulp.task("server", () => {
  const { input } = paths.server;
  browserSync.init({
    server: {
      // 访问目录，其值可以是字符串、对象
      baseDir: input,
      index: "index.html",
      middleware: [
        // 自定义中间件，此时可以通过 node 来 mock 数据
        function (req, res, next) {
          console.log("Hi from first middleware");
          next();
          var urlObj = url.parse(req.url, true),
                    method = req.method,
                    paramObj = urlObj.query;
                // mock数据
                mockApi(res, urlObj.pathname, paramObj, next);
        },
        // 通过代理mock数据
        // createProxyMiddleware("/api", {
        //   target: "http://127.0.0.1:5000",
        //   changeOrigin: true, // for vhosted sites, changes host header to match to target's host
        //   pathRewrite: {
        //     "^/api": "",
        //   },
        //   logLevel: "debug",
        // }),
      ],
    },
    https: false,
    // proxy: "", // 域名或 ip，设置代理
  });
  gulp
    .watch(["src/**/*.ejs"], gulp.series(["ejs", "inject"]))
    .on("change", browserSync.reload);
});

/**
 * watch 侦听，侦听文件变化，实现自动打包，自动刷新浏览器。
 * 自动打包，要求速度要快，所以
 * 1. 尽可能的将监听任务拆开
 * 2. 减少开发模式下的功耗，如不进行压缩处理，特别是图片的压缩需要时间较长。
 */
gulp.task("watch", () => {
  gulp
    .watch(["src/**/*.ejs"], gulp.series(["ejs", "inject"]))
    .on("change", browserSync.reload);
});

/**
 * 执行顺序
 * Gulp 4.0 及以上版本 gulp.series 顺序执行，gulp.paralle 并行执行
 */
gulp.task(
  "dev",
  gulp.series(
    "clean",
    "copy"
    // gulp.parallel(
    // "favicons",
    // "html"
    // "js",
    // "scss",
    // "ejs"
    // "css",
    // "images",
    // "watch",
    // "server",
    // "clean",
    // "copy"
    // gulp.parallel(
    //   // 'copy',
    //   "html",
    //   "js",
    //   "scss",
    //   "images",
    //   "watch",
    //   "server",
    //   function () {
    //     console.log("gulp start dev");
    //   },
    // ),
    // ),
    // "inject",
    // "watch",
    // "server"
  )
);

gulp.task("build", () => {});
